home *** CD-ROM | disk | FTP | other *** search
- #include <stdio.h>
- #include <ctype.h>
- #include <string.h>
- #include <stdarg.h>
- #include "lib.h"
-
- /*
- * %efg were loosing big time
- * fixed ++jrb
- * all floating conversion now done by atof. much is gained by this.
- * ++jrb
- *
- * hacked to use stdarg by bm
- */
-
- #ifndef __NO_FLOAT__
- #define FLOATS 1
- #endif
-
- #ifndef TRUE
- #define TRUE 1
- #define FALSE 0
- #endif
-
- #define skip() \
- while (isspace(c)) { charcnt++; c = (*get)(ip); if (c == EOF) goto done; }
- #define TEN_MUL(X) ((((X) << 2) + (X)) << 1)
-
- #if FLOATS
- /* fp scan actions */
- #define F_NADA 0 /* just change state */
- #define F_SIGN 1 /* set sign */
- #define F_ESIGN 2 /* set exponent's sign */
- #define F_INT 3 /* adjust integer part */
- #define F_FRAC 4 /* adjust fraction part */
- #define F_EXP 5 /* adjust exponent part */
- #define F_QUIT 6
-
- #define NSTATE 8
- #define FS_INIT 0 /* initial state */
- #define FS_SIGNED 1 /* saw sign */
- #define FS_DIGS 2 /* saw digits, no . */
- #define FS_DOT 3 /* saw ., no digits */
- #define FS_DD 4 /* saw digits and . */
- #define FS_E 5 /* saw 'e' */
- #define FS_ESIGN 6 /* saw exp's sign */
- #define FS_EDIGS 7 /* saw exp's digits */
-
- #define FC_DIG 0
- #define FC_DOT 1
- #define FC_E 2
- #define FC_SIGN 3
-
- /* given transition,state do what action? */
- static const int fp_do[][NSTATE] = {
- {F_INT,F_INT,F_INT,
- F_FRAC,F_FRAC,
- F_EXP,F_EXP,F_EXP}, /* see digit */
- {F_NADA,F_NADA,F_NADA,
- F_QUIT,F_QUIT,F_QUIT,F_QUIT,F_QUIT}, /* see '.' */
- {F_QUIT,F_QUIT,
- F_NADA,F_QUIT,F_NADA,
- F_QUIT,F_QUIT,F_QUIT}, /* see e/E */
- {F_SIGN,F_QUIT,F_QUIT,F_QUIT,F_QUIT,
- F_ESIGN,F_QUIT,F_QUIT}, /* see sign */
- };
- /* given transition,state what is new state? */
- static const int fp_ns[][NSTATE] = {
- {FS_DIGS,FS_DIGS,FS_DIGS,
- FS_DD,FS_DD,
- FS_EDIGS,FS_EDIGS,FS_EDIGS}, /* see digit */
- {FS_DOT,FS_DOT,FS_DD,
- }, /* see '.' */
- {0,0,
- FS_E,0,FS_E,
- }, /* see e/E */
- {FS_SIGNED,0,0,0,0,
- FS_ESIGN,0,0}, /* see sign */
- };
- /* which states are valid terminators? */
- static const int fp_sval[NSTATE] = {
- 0,0,1,0,1,1,1,1
- };
- #endif
-
- #ifdef __STDC__
- int _scanf(register FILE *ip, int (*get)(FILE *),
- int (*unget)(int, FILE *), const char *_fmt, va_list args)
- #else
- int
- _scanf(ip, get, unget, _fmt, args)
- FILE *ip;
- int (*get) __PROTO((FILE *));
- int (*unget) __PROTO((int, FILE *));
- const char *_fmt;
- char **args;
- #endif
- {
- register long n;
- register int c, width, lval, sval, cnt = 0, charcnt = 1;
- #if defined (PRINTF_LONGLONG) || defined (__STDC__)
- register int llval = 0;
- #endif
- #ifdef PRINTF_LONGLONG
- register long long lln;
- #endif
- int store, neg, base, endnull, c2;
- register unsigned char *p = 0;
- const unsigned char *fmt = (const unsigned char *) _fmt;
- char delim[256], *q;
- #if FLOATS
- double fx;
- char fbuf[128], *fbp;
- int fstate, trans;
- extern double atof __PROTO((const char *));
- #endif
-
- c = (*get)(ip);
- while (*fmt)
- {
- if (*fmt == '%')
- {
- width = -1;
- lval = FALSE;
- #if defined (PRINTF_LONGLONG) || defined (__STDC__)
- llval = FALSE;
- #endif
- sval = FALSE;
- store = TRUE;
-
- if (*++fmt == '*')
- {
- store = FALSE;
- ++fmt;
- }
-
- if (isdigit (*fmt)) /* width digit(s) */
- {
- width = *fmt++ - '0';
- while (isdigit (*fmt))
- width = TEN_MUL (width) + *fmt++ - '0';
- }
-
- fmtnxt:
- switch(*fmt++)
- {
- case 'l': /* long data */
- #ifdef PRINTF_LONGLONG
- if (lval)
- llval = TRUE;
- #endif
- lval = TRUE;
- goto fmtnxt;
-
- #ifdef __STDC__
- case 'L': /* long double */
- llval = TRUE;
- goto fmtnxt;
- #endif
-
- case 'h': /* short data (for compatibility) */
- sval = TRUE;
- goto fmtnxt;
-
- case 'i': /* any-base numeric */
- base = 0;
- neg = -1;
- goto numfmt;
-
- case 'b': /* unsigned binary, non-standard */
- case 'B': /* non-standard */
- base = 2;
- neg = 0;
- goto numfmt;
-
- case 'o': /* unsigned octal */
- case 'O': /* non-standard */
- base = 8;
- neg = 0;
- goto numfmt;
-
- case 'p': /* pointer */
- lval = TRUE;
- #ifdef PRINTF_LONGLONG
- llval = FALSE;
- #endif
- /* fall through */
-
- case 'x': /* unsigned hexadecimal */
- case 'X': /* non-standard */
- base = 16;
- neg = 0;
- goto numfmt;
-
- case 'd': /* SIGNED decimal */
- case 'D': /* non-standard */
- base = 10;
- neg = -1;
- goto numfmt;
-
- case 'u': /* unsigned decimal */
- case 'U': /* non-standard */
- base = 10;
- neg = 0;
- numfmt:
- skip();
- memset (delim, -1, sizeof (delim));
- if (isupper(fmt[-1])) {
- /* non-standard */
- #ifdef PRINTF_LONGLONG
- if (lval) llval = TRUE;
- #endif
- lval = TRUE;
- }
- n = 0;
- #ifdef PRINTF_LONGLONG
- lln = 0;
- #endif
- if (width == 0)
- goto savnum;
- if (!base)
- {
- if (c == '%') /* non-standard */
- {
- base = 2;
- neg = 0;
- goto skip1;
- }
- else if (c == '0')
- {
- if (--width == 0)
- goto savnum;
- charcnt++;
- c = (*get)(ip);
- if (c == EOF)
- goto savnum;
- if ((c != 'x')
- && (c != 'X'))
- {
- base = 8;
- neg = 0;
- for (c2 = 0; c2 < 8; c2++)
- delim[c2 + '0'] = c2;
- goto zeroin;
- }
- base = 16;
- neg = 0;
- goto skip1;
- }
- else
- base = 10;
- }
-
- /* Check for 0x prefix */
- if (base == 16 && c == '0')
- {
- if (--width == 0)
- goto savnum;
- charcnt++;
- c = (*get) (ip);
- if (c == EOF)
- goto savnum;
- if (c == 'x' || c == 'X')
- goto skip1;
- /* else unget the character, it may already be a
- non-digit and the number would be rejected */
- charcnt--;
- (*unget) (c, ip);
- c = '0';
- }
- else if (neg == -1)
- {
- neg = c == '-';
- if (neg || c == '+')
- {
- skip1:
- if (--width == 0)
- goto done;
- charcnt++;
- c = (*get)(ip);
- if (c == EOF)
- goto done;
- }
- }
-
- /* delim[c] -> value of c or -1 */
- p = (unsigned char *) "FEDCBAfedcba9876543210";
- q = "\17\16\15\14\13\12\17\16\15\14\13\12\11\10\7\6\5\4\3\2\1\0";
- if (base < 16)
- {
- /* skip invalid digits */
- p += 22 - base;
- q += 22 - base;
- }
- while (*p)
- delim[*p++] = *q++;
-
- if (delim[c] == (char) -1)
- goto done;
-
- while (width--)
- {
- #ifdef PRINTF_LONGLONG
- if (llval)
- lln = (lln * base) + delim[c];
- else
- #endif
- n = (n * base) + delim[c];
- charcnt++;
- c = (*get)(ip);
- if (c == EOF)
- break;
- zeroin:
- if (delim[c] == (char) -1)
- break;
- }
- savnum:
- if (store)
- {
- #ifdef __STDC__
- p = va_arg(args, void *);
- #else
- p = ((unsigned char *) *args);
- #endif
- #ifdef PRINTF_LONGLONG
- if (llval)
- {
- if (neg)
- lln=-lln;
- *((long long*) p) = lln;
- }
- else
- #endif
- {
- if (neg)
- n = -n;
- if (lval)
- *((long*) p) = n;
- else if (sval)
- *((short *) p) = (short) n;
- else
- *((int *) p) = (int) n;
- ++cnt;
- }
- }
- break;
-
- #if FLOATS
- case 'E': /* non-standard */
- case 'F':
- case 'G':
- lval = TRUE;
- /* fall through */
-
- case 'e': /* float */
- case 'f':
- case 'g':
- skip();
-
- memset (delim, -1, sizeof (delim));
- for (c2 = '0'; c2 <= '9'; c2++)
- delim[c2] = FC_DIG;
- delim['.'] = FC_DOT;
- delim['+'] = delim['-'] = FC_SIGN;
- delim['e'] = delim['E'] = FC_E;
-
- fstate = FS_INIT;
- fbp = fbuf;
- while (c != EOF && width--) {
- trans = delim[c];
- if (trans == (char) -1)
- break;
- if (fbp - fbuf + 1 < sizeof (fbuf))
- *fbp++ = c;
-
- if (fp_do[trans][fstate] == F_QUIT)
- break;
- fstate = fp_ns[trans][fstate];
- charcnt++;
- c = (*get)(ip);
- }
-
- *fbp = '\0';
- if (!fp_sval[fstate])
- goto done;
- if (store) {
- fx = (*fbuf == '\0') ? 0.0 : atof(fbuf);
- #ifdef __STDC__
- p = va_arg(args, void *);
- #else
- p = (unsigned char *) *args;
- #endif
- #ifdef __STDC__
- /* partial support for long double */
- #ifdef __M68881__ /* currently only with m68881 */
- if (llval)
- *(long double *) p = (long double) fx;
- else
- #endif
- #endif
- if (lval)
- *((double *) p) = fx;
- else
- *((float *) p) = (float)fx;
- ++cnt;
- }
- break;
- #endif
-
- case 'n':
- if (store) {
- #ifdef __STDC__
- p = va_arg(args, void *);
- #else
- p = (unsigned char *) *args;
- #endif
- /* Compensate for lookahead */
- *((int *) p) = charcnt - 1;
- }
- break;
-
- case 'c': /* character data */
- if (width == -1)
- width = 1;
- endnull = FALSE;
- memset (delim, 0, sizeof (delim));
- if (c == EOF)
- goto done;
- goto strproc;
-
- case '[': /* string w/ delimiter set */
- endnull = TRUE;
-
- /* get delimiters */
- neg = FALSE;
- if (*fmt == '^')
- {
- fmt++;
- neg = TRUE;
- }
-
- memset (delim, !neg, sizeof (delim));
-
- if ((*fmt == ']') || (*fmt == '-'))
- {
- delim[*fmt++] = neg;
- }
-
- while (c2 = *fmt++, c2 != ']')
- {
- if (c2 == '\0')
- break;
- if (*fmt == '-' && fmt[1] && fmt[1] != ']')
- {
- while (c2 <= fmt[1])
- delim[c2++] = neg;
- fmt += 2;
- }
- else
- delim[c2] = neg;
- }
-
- goto strproc;
-
- case 's': /* string data */
- skip();
- memset (delim, 0, sizeof (delim));
- delim['\t'] = 1;
- delim['\n'] = 1;
- delim['\v'] = 1;
- delim['\f'] = 1;
- delim['\r'] = 1;
- delim[' '] = 1;
- endnull = TRUE;
- strproc:
- /* process string */
- #ifdef __STDC__
- if (store)
- p = va_arg(args, void *);
- #else
- p = ((unsigned char *) *args);
- #endif
-
- /* if the 1st char fails, match fails */
- if (width)
- {
- if (c == EOF || delim[c])
- {
- if (endnull)
- if (store)
- *p = '\0';
- goto done;
- }
- }
-
- for (;;) /* FOREVER */
- {
- if (store)
- *p++ = c;
- charcnt++;
- c = (*get)(ip);
- if (c == EOF || --width == 0)
- break;
- if (delim[c])
- break;
- }
-
- if (store)
- {
- if (endnull)
- *p = '\0';
- ++cnt;
- }
- break;
-
- case '%':
- --fmt;
- goto cmatch;
-
- default:
- goto done;
- }
- }
- else if (isspace(*fmt)) /* skip whitespace */
- {
- fmt++;
- skip();
- }
- else
- { /* normal match char */
- cmatch:
- if (c != *fmt++)
- goto done;
- charcnt++;
- c = (*get)(ip);
- }
-
- #ifdef __STDC__
- /* nothing to do */
- #else
- if (store)
- args++;
- #endif
- }
-
- done: /* end of scan */
- if (c != EOF)
- (*unget) (c, ip);
- if (c == EOF && cnt == 0)
- return(EOF);
- return(cnt);
- }
-